package base

import (
	"net/http"
	"time"
	"walnut/internal/model/base"
	"walnut/kernel"

	"github.com/golang-jwt/jwt/v5"
)

// 注册
func Register(w http.ResponseWriter, r *http.Request) {
	var (
		u *base.User
	)
	if kernel.Qe(w, kernel.ShouldBindJSON(r, &u)) {
		return
	}
	// 检查是否存在相同的用户名
	rows, err := kernel.DB.Query("select id from user where username = ?", u.Username)
	if err == nil {
		kernel.Error(w, err)
		return
	}
	rows.Next()
	if kernel.Qe(w, rows.Scan(&u.ID)) {
		return
	}
	// 没有错误，说明存在相同的用户名，返回错误信息，不创建用户
	if u.ID > 0 {
		kernel.Error(w, base.ErrUserExists)
		return
	}
	// 加密密码
	if err := u.BcryptPassword(); err != nil {
		kernel.Error(w, err)
		return
	}
	// 创建用户
	_, err = kernel.DB.Exec("insert into user (username,password) values (?,?)", u.Username, u.Password)
	if err != nil {
		kernel.Error(w, err)
		return
	}
	kernel.Success(w)
}

// 登录
func Login(w http.ResponseWriter, r *http.Request) {
	var (
		u *base.User
	)
	if kernel.Qe(w, kernel.ShouldBindJSON(r, &u)) {
		return
	}
	// 检查是否存在用户名
	rows, err := kernel.DB.Query("select id,username,password from user where username = ?", u.Username)
	if err != nil {
		kernel.Error(w, err)
		return
	}
	rows.Next()
	if kernel.Qe(w, rows.Scan(&u.ID, &u.Username, &u.Password)) {
		return
	}
	if u.ID == 0 {
		kernel.Error(w, base.ErrUserNotFound)
		return
	}
	// 检查密码是否正确
	if kernel.Qe(w, u.ComparePassword(u.Password), func(err error) error {
		return base.ErrWrongPassword
	}) {
		return
	}
	// 设置过期时间
	expirationTime := time.Now().Add(kernel.Conf.JWT.TTL * time.Hour)
	// 生成token
	claims := &kernel.Claims{
		UserId:   u.ID,
		Username: u.Username,
		RegisteredClaims: jwt.RegisteredClaims{
			Issuer:    kernel.Conf.JWT.Issuer,
			ExpiresAt: jwt.NewNumericDate(expirationTime),
		},
	}
	t, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(kernel.Conf.JWT.SecretKey))
	if err != nil {
		kernel.Error(w, err)
		return
	}
	// 将 JWT 令牌作为响应返回给客户端
	http.SetCookie(w, &http.Cookie{
		Name:    kernel.Conf.JWT.KeyName,
		Value:   t,
		Expires: expirationTime,
	})
	kernel.Data(w, &base.LoginResult{Token: t})
}

// 登录信息
func Info(w http.ResponseWriter, r *http.Request) {
	var ck kernel.CtxKey = "claims"
	claims := r.Context().Value(ck).(kernel.Claims)
	kernel.Data(w, &base.LoginResult{Claims: &claims})
}
